﻿using Frameworks;
using Network.Core.RPC;
using Network.General.Protobuf;
using Network.General.Server;
using Network.Utils;
using System.Text;
using UnityEngine;

namespace Server
{
    public class OnlineManager : Singleton<OnlineManager>
    {
        private MapList<uint, UserData> _mapUserData;

        private NetManager _net;
        private uint _lastCheckTimeoutStamp;

        private OnlineManager() { }

        public override void OnSingletonInit()
        {
            base.OnSingletonInit();
        }

        public override void Dispose()
        {
            _net.Clean();

            base.Dispose();
        }

        public void Init(ServerContext context)
        {
            _net = context.net;
            _net.SetAuthCmd(ProtoCmd.LoginReq);
            _net.AddListener<LoginReq>(ProtoCmd.LoginReq, onLoginRequest);
            _net.AddListener<HeartBeatReq>(ProtoCmd.HeartBeatReq, onHeartBeatRequest);

            _net.Rpc.RegisterListener(this);
            _mapUserData = new MapList<uint, UserData>();
        }

        public void Dump()
        {
            StringBuilder sb = new StringBuilder();
            UserData[] list = _mapUserData.ToArray();
            for (int i = 0; i < list.Length; i++)
            {
                sb.AppendLine("\t" + list[i].ToString());
            }

            Debug.Log(string.Format("\nUser ({0}):\n{1}", _mapUserData.Count, sb));
        }

        private void onLoginRequest(ISession session, uint index, LoginReq req)
        {
            bool success = false;

            UserData ud = GetUserData(req.account);
            if (ud == null)
            {
                // 正常登录,这里简单地使用SessionId作为UserId
                ud = CreateUserData(session.Id, req.account);
                ud.svrdata.online = true;
                ud.svrdata.lastHeartBeatTime = (uint)TimeUtils.GetTotalSecondsSince1970();
                session.AuthToken = ud.id;
                success = true;
            }
            else
            {
                if (req.id == ud.id)
                {
                    // 重新登录
                    ud.svrdata.online = true;
                    ud.svrdata.lastHeartBeatTime = (uint)TimeUtils.GetTotalSecondsSince1970();
                    session.AuthToken = ud.id;
                    success = true;
                }
                else
                {
                    // 正常登录,但是尝试占用已有的名字
                    if (!ud.svrdata.online)
                    {
                        // 如果该名字已经离线,则可以占用
                        ud.svrdata.online = true;
                        ud.svrdata.lastHeartBeatTime = (uint)TimeUtils.GetTotalSecondsSince1970();
                        session.AuthToken = ud.id;
                        success = true;
                    }
                }
            }

            if (success)
            {
                LoginRsp rsp = new LoginRsp();
                rsp.ret = ReturnCode.Success;
                rsp.userdata = ud;
                _net.Send(session, new ProtocolHead() { index = index }, ProtoCmd.LoginRsp, rsp);
            }
            else
            {
                LoginRsp rsp = new LoginRsp();
                rsp.ret = new ReturnCode(1, "名字已经被占用了！");
                _net.Send(session, new ProtocolHead() { index = index }, ProtoCmd.LoginRsp, rsp);
            }
        }

        private void onHeartBeatRequest(ISession session, uint index, HeartBeatReq req)
        {
            UserData ud = GetUserData(session.Id);
            if (ud != null)
            {
                ud.svrdata.lastHeartBeatTime = (uint)TimeUtils.GetTotalSecondsSince1970();

                session.Ping = req.ping;
                HeartBeatRsp rsp = new HeartBeatRsp();
                rsp.ret = ReturnCode.Success;
                rsp.timestamp = req.timestamp;
                _net.Send(session, new ProtocolHead() { index = index }, ProtoCmd.HeartBeatRsp, rsp);
            }
            else
            {
                Debug.Log(string.Format("找不到Session 对应的UserData! session:{0}", session));
            }
        }

        [RPCRequest]
        private void Logout(ISession session)
        {
            OnlineManager.Instance.ReleaseUserData(session.Id);
            _net.Rpc.Return();
        }

        public UserData CreateUserData(uint id, string account)
        {
            UserData data = new UserData();
            data.id = id;
            data.account = account;
            _mapUserData.Add(id, data);
            return data;
        }

        public void ReleaseUserData(uint id)
        {
            _mapUserData.Remove(id);
        }

        public UserData GetUserData(string account)
        {
            int cnt = _mapUserData.Count;
            var list = _mapUserData.AsList();
            for (int i = 0; i < cnt; i++)
            {
                if (list[i].account == account)
                {
                    return list[i];
                }
            }
            return null;
        }

        public UserData GetUserData(uint id)
        {
            return _mapUserData[id];
        }
    }
}